package com.night.icm.service.base.service;

import com.github.wenhao.jpa.PredicateBuilder;
import com.github.wenhao.jpa.Specifications;
import com.night.icm.common.exception.AlreadyExistsDataException;
import com.night.icm.common.exception.NoSuchDataException;
import com.night.icm.common.jpa.PageHelper;
import com.night.icm.common.service.PageDataUtil;
import com.night.icm.common.utils.PageDataDTO;
import com.night.icm.common.utils.SimpleDataDTO;
import com.night.icm.model.base.SystemDictionaryDTO;
import com.night.icm.model.base.SystemDictionaryValueDTO;
import com.night.icm.persistence.base.entity.SystemDictionary;
import com.night.icm.persistence.base.entity.SystemDictionaryValue;
import com.night.icm.persistence.base.repository.SystemDictionaryRepository;
import com.night.icm.persistence.base.repository.SystemDictionaryValueRepository;
import com.night.icm.service.base.mapper.DictionaryMapper;
import com.night.icm.service.base.mapper.DictionaryValueMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * DictionaryServiceImpl
 *
 * @author Liao ZhiYong
 * @date 2019/12/22
 */
@Service
@Transactional(readOnly = true, rollbackFor = Exception.class)
public class DictionaryServiceImpl implements DictionaryService {

    private final SystemDictionaryRepository systemDictionaryRepository;
    private final SystemDictionaryValueRepository systemDictionaryValueRepository;
    private final DictionaryMapper dictionaryMapper;
    private final DictionaryValueMapper dictionaryValueMapper;

    @Autowired
    public DictionaryServiceImpl(SystemDictionaryRepository systemDictionaryRepository, SystemDictionaryValueRepository systemDictionaryValueRepository, DictionaryMapper dictionaryMapper, DictionaryValueMapper dictionaryValueMapper) {
        this.systemDictionaryRepository = systemDictionaryRepository;
        this.systemDictionaryValueRepository = systemDictionaryValueRepository;
        this.dictionaryMapper = dictionaryMapper;
        this.dictionaryValueMapper = dictionaryValueMapper;
    }

    /**
     * 查找所有字典
     *
     * @return 字典集合
     */
    @Override
    public List<SystemDictionaryDTO> findAll() {
        List<SystemDictionary> entitys = this.systemDictionaryRepository.findAll();
        return this.dictionaryMapper.toList(entitys);
    }

    /**
     * 删除字典
     *
     * @param id 字典id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteById(String id) {
        this.systemDictionaryRepository.deleteById(Long.valueOf(id));
    }

    /**
     * 新建字典
     *
     * @param systemDictionaryDTO 字典信息
     * @return 字典
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemDictionaryDTO create(SystemDictionaryDTO systemDictionaryDTO) {
        SystemDictionary systemDictionary = this.dictionaryMapper.toEntity(systemDictionaryDTO);
        systemDictionary = this.systemDictionaryRepository.save(systemDictionary);
        return this.dictionaryMapper.toDTO(systemDictionary);
    }

    /**
     * 更新字典
     *
     * @param id                  字典id
     * @param systemDictionaryDTO 字典信息
     * @return 字典信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemDictionaryDTO update(String id, SystemDictionaryDTO systemDictionaryDTO) {
        Optional<SystemDictionary> optional = this.systemDictionaryRepository.findById(Long.valueOf(id));
        if (!optional.isPresent()) {
            throw new NoSuchDataException(id);
        }
        SystemDictionary systemDictionary = optional.get();
        this.dictionaryMapper.updateEntity(systemDictionaryDTO, systemDictionary);
        this.systemDictionaryRepository.save(systemDictionary);
        return this.dictionaryMapper.toDTO(systemDictionary);
    }

    /**
     * 分页查询字典信息
     *
     * @param page 页号，从0开始
     * @param size 每页纪录条数
     * @param sort 排序字段, 例如：字段1,asc,字段2,desc
     * @param code 字典编号
     * @param name 字典名称
     * @return 字典分页数据
     */
    @Override
    public PageDataDTO<SystemDictionaryDTO> findOnePage(int page, int size, String sort, String code, String name) {
        PredicateBuilder<SystemDictionary> pb = Specifications.<SystemDictionary>and()
                .like(StringUtils.isNotBlank(code), "code", "%" + code + "%")
                .like(StringUtils.isNotBlank(name), "name", "%" + name + "%");
        Page<SystemDictionary> entity = this.systemDictionaryRepository.findAll(pb.build(), PageHelper.generatePageRequest(page, size, sort));
        List<SystemDictionaryDTO> toList = this.dictionaryMapper.toList(entity.getContent());
        return PageDataUtil.toPageData(entity, toList);
    }

    /**
     * 新建字典值
     *
     * @param dictionaryId             字典id
     * @param systemDictionaryValueDTO 字典值信息
     * @return 字典值
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemDictionaryValueDTO createValue(String dictionaryId, SystemDictionaryValueDTO systemDictionaryValueDTO) {
        Optional<SystemDictionary> optionalSystemDictionary = this.systemDictionaryRepository.findById(Long.valueOf(dictionaryId));
        if (!optionalSystemDictionary.isPresent()) {
            throw new NoSuchDataException(dictionaryId);
        }
        SystemDictionary systemDictionary = optionalSystemDictionary.get();
        SystemDictionaryValue systemDictionaryValue = this.dictionaryValueMapper.toEntity(systemDictionaryValueDTO);
        // 接口创建的数据，systemInitialized 肯定为 false
        systemDictionaryValue.setSystemInitialized(false);
        systemDictionaryValue.setDictionary(systemDictionary);
        systemDictionaryValue = this.systemDictionaryValueRepository.saveAndFlush(systemDictionaryValue);
        if (systemDictionary.getValues() != null) {
            systemDictionary.getValues().add(systemDictionaryValue);
        }
        return this.dictionaryValueMapper.toDTO(systemDictionaryValue);
    }

    /**
     * 修改一个字典值
     *
     * @param dictionaryId             字典id
     * @param valueId                  字典值id
     * @param systemDictionaryValueDTO 字典值信息
     * @return 字典值
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public SystemDictionaryValueDTO updateValue(String dictionaryId, String valueId, SystemDictionaryValueDTO systemDictionaryValueDTO) {
        Optional<SystemDictionary> optionalSystemDictionary = this.systemDictionaryRepository.findById(Long.valueOf(dictionaryId));
        Optional<SystemDictionaryValue> optionalSystemDictionaryValue = this.systemDictionaryValueRepository.findById(Long.valueOf(valueId));
        if (!optionalSystemDictionary.isPresent() || !optionalSystemDictionaryValue.isPresent()) {
            throw new NoSuchDataException(dictionaryId + "or" + valueId);
        }
        SimpleDataDTO<Boolean> value = checkDictionaryValue(dictionaryId, valueId, systemDictionaryValueDTO.getKey());
        if (Boolean.TRUE.equals(value.getData())) {
            throw new AlreadyExistsDataException();
        }
        SystemDictionary systemDictionary = optionalSystemDictionary.get();
        SystemDictionaryValue systemDictionaryValue = optionalSystemDictionaryValue.get();
        this.dictionaryValueMapper.updateEntity(systemDictionaryValueDTO, systemDictionaryValue);
        if (systemDictionary.getValues() != null) {
            systemDictionary.getValues().add(systemDictionaryValue);
        }
        systemDictionaryValue.setDictionary(systemDictionary);
        systemDictionaryValue = this.systemDictionaryValueRepository.saveAndFlush(systemDictionaryValue);
        return this.dictionaryValueMapper.toDTO(systemDictionaryValue);
    }

    /**
     * 检查字典值Key是否唯一
     *
     * @param dictionaryId      字典id
     * @param dictionaryValueId 字典值id
     * @param key               字典值key
     * @return 是否唯一
     */
    @Override
    public SimpleDataDTO<Boolean> checkDictionaryValue(String dictionaryId, String dictionaryValueId, String key) {
        SimpleDataDTO<Boolean> simpleDataDTO = new SimpleDataDTO<>();
        Long valueId = this.systemDictionaryValueRepository.findByDictionaryAndKey(Long.valueOf(dictionaryId), key);
        if (dictionaryValueId == null) {
            dictionaryValueId = "null";
        }
        if (valueId != null && !dictionaryValueId.equals(valueId.toString())) {
            simpleDataDTO.setData(true);
        } else {
            simpleDataDTO.setData(false);
        }
        return simpleDataDTO;
    }

    /**
     * 检查字典Code是否唯一
     *
     * @param dictionaryId 字典id
     * @param code         字典code
     * @return 是否唯一
     */
    @Override
    public SimpleDataDTO<Boolean> checkDictionaryCode(String dictionaryId, String code) {
        SimpleDataDTO<Boolean> simpleDataDTO = new SimpleDataDTO<>();
        SystemDictionary systemDictionary = this.systemDictionaryRepository.findByCode(code);
        if (dictionaryId == null) {
            dictionaryId = "null";
        }
        if (systemDictionary != null && !dictionaryId.equals(systemDictionary.getId().toString())) {
            simpleDataDTO.setData(true);
        } else {
            simpleDataDTO.setData(false);
        }
        return simpleDataDTO;
    }

    /**
     * 删除一个字段值
     *
     * @param dictionaryId 字典id
     * @param valueId      字典值id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteValue(String dictionaryId, String valueId) {
        Optional<SystemDictionary> optionalDictionary = this.systemDictionaryRepository.findById(Long.valueOf(dictionaryId));
        Optional<SystemDictionaryValue> optionalDictionaryValue = this.systemDictionaryValueRepository.findById(Long.valueOf(valueId));
        if (!optionalDictionary.isPresent()) {
            throw new NoSuchDataException(dictionaryId);
        }
        if (!optionalDictionaryValue.isPresent()) {
            throw new NoSuchDataException(valueId);
        }
        SystemDictionary systemDictionary = optionalDictionary.get();
        SystemDictionaryValue systemDictionaryValue = optionalDictionaryValue.get();
        // 不允许删除系统初始化的数据
        if (Boolean.TRUE.equals(systemDictionaryValue.getSystemInitialized())) {
            return;
        }
        systemDictionary.getValues().remove(systemDictionaryValue);
        this.systemDictionaryValueRepository.delete(systemDictionaryValue);
    }

    /**
     * 根据字典编号查找信息, 通常用于下拉框数据查找, 无需权限
     *
     * @param code 字典编号
     * @param all  是否为全部值（包括available为false的值）
     * @return 字典
     */
    @Override
    public SystemDictionaryDTO findByCode(String code, Boolean all) {
        SystemDictionary systemDictionary = this.systemDictionaryRepository.findByCode(code);
        if (systemDictionary != null) {
            SystemDictionaryDTO dictionaryDTO = this.dictionaryMapper.toDTO(systemDictionary);
            recursionSetChildrenDictionaryValuesDTO(dictionaryDTO, systemDictionary, all);
            return dictionaryDTO;
        } else {
            throw new NoSuchDataException(code);
        }
    }

    /**
     * 递归遍历子字典与子字典DTO,设置SystemDictionaryValueDTOs
     *
     * @param dictionaryDTO 字典DTO
     * @param dictionary    字典对象
     * @param all           是否加载全部，包括available为false的值
     */
    private void recursionSetChildrenDictionaryValuesDTO(SystemDictionaryDTO dictionaryDTO, SystemDictionary dictionary, Boolean all) {
        if (dictionary.getValues() != null && !dictionary.getValues().isEmpty()) {
            List<SystemDictionaryValueDTO> dictionaryValueDtoList = new ArrayList<>();
            for (SystemDictionaryValue dictionaryValue : dictionary.getValues()) {
                if (all || dictionaryValue.getAvailable()) {
                    dictionaryValueDtoList.add(this.dictionaryValueMapper.toDTO(dictionaryValue));
                }
            }
            dictionaryDTO.setValues(dictionaryValueDtoList);
        }
    }
}